/*	--*- c++ -*--
 * Copyright (C) 2017 Enrico Scholz <enrico.scholz@sigma-chemnitz.de>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef HH_ENSC_BAYER_RGB_CONVERT_INTERNAL_HH
#define HH_ENSC_BAYER_RGB_CONVERT_INTERNAL_HH

#include "bayer2rgb.h"
#include <endian.h>

// the output format
template <typename FMT>
struct _outfmt {
	typedef FMT		fmt_t;

	static inline void zero_alpha(fmt_t &p) {
	}
};

template <typename FMT>
struct _outfmt_padded {
	typedef FMT		fmt_t;

	static inline void zero_alpha(fmt_t &p) {
		p.pad = 0;
	}
};

template <typename FMT>
struct outfmt {
};

template <>
struct outfmt<struct rgbx32_pixel>: public _outfmt_padded<struct rgbx32_pixel> {
	static unsigned int const	max_rb = 255;
	static unsigned int const	bpp_rb = 8;
	static unsigned int const	max_g  = 255;
	static unsigned int const	bpp_g  = 8;
};

template <>
struct outfmt<struct bgrx32_pixel>: public _outfmt_padded<struct bgrx32_pixel> {
	static unsigned int const	max_rb = 255;
	static unsigned int const	bpp_rb = 8;
	static unsigned int const	max_g  = 255;
	static unsigned int const	bpp_g  = 8;
};

template <>
struct outfmt<struct xbgr32_pixel>: public _outfmt_padded<struct xbgr32_pixel> {
	static unsigned int const	max_rb = 255;
	static unsigned int const	bpp_rb = 8;
	static unsigned int const	max_g  = 255;
	static unsigned int const	bpp_g  = 8;
};

template <>
struct outfmt<struct xrgb32_pixel>: public _outfmt_padded<struct xrgb32_pixel> {
	static unsigned int const	max_rb = 255;
	static unsigned int const	bpp_rb = 8;
	static unsigned int const	max_g  = 255;
	static unsigned int const	bpp_g  = 8;
};

template <>
struct outfmt<struct rgb16_pixel>: public _outfmt<struct rgb16_pixel> {
	static unsigned int const	max_rb = 31;
	static unsigned int const	bpp_rb = 5;
	static unsigned int const	max_g  = 63;
	static unsigned int const	bpp_g  = 6;
};

struct bitfmt_10le {
	uint16_t			v;
};

struct bitfmt_12le {
	uint16_t			v;
};

struct bitfmt_16le {
	uint16_t			v;
};

struct bitfmt_10be {
	uint16_t			v;
};

struct bitfmt_12be {
	uint16_t			v;
};

struct bitfmt_16be {
	uint16_t			v;
};

// the input formats
template <typename T, unsigned int BPP>
struct _infmt {
	typedef T			bitfmt_t;
	static size_t const		sz = sizeof(T);
	static unsigned int const	bpp = BPP;
	static unsigned int const	max = (1u << BPP) - 1u;
};

template <typename T>
struct infmt {
};

template <>
struct infmt<uint8_t>: public _infmt<uint8_t, 8> {
	static inline unsigned int as_uint(bitfmt_t v) {
		return v;
	}

	static inline bitfmt_t as_bitfmt(unsigned int v) {
		return v;
	}
};

template <>
struct infmt<struct bitfmt_10le>: public _infmt<bitfmt_10le, 10> {
	static inline unsigned int as_uint(bitfmt_t v) {
		return le16toh(v.v) & 0x3ff;
	}

	static inline bitfmt_t as_bitfmt(unsigned int v) {
		return bitfmt_t{ htole16(v) };
	}
};

template <>
struct infmt<struct bitfmt_12le>: public _infmt<bitfmt_12le, 12> {
	static inline unsigned int as_uint(bitfmt_t v) {
		return le16toh(v.v) & 0xfff;
	}

	static inline bitfmt_t as_bitfmt(unsigned int v) {
		return bitfmt_t{ htole16(v) };
	}
};

template <>
struct infmt<struct bitfmt_16le>: public _infmt<bitfmt_16le, 16> {
	static inline unsigned int as_uint(bitfmt_t v) {
		return le16toh(v.v);
	}

	static inline bitfmt_t as_bitfmt(unsigned int v) {
		return bitfmt_t{ htole16(v) };
	}
};

template <>
struct infmt<struct bitfmt_10be>: public _infmt<bitfmt_10be, 10> {
	static inline unsigned int as_uint(bitfmt_t v) {
		return be16toh(v.v) & 0x3ff;
	}

	static inline bitfmt_t as_bitfmt(unsigned int v) {
		return bitfmt_t{ htobe16(v) };
	}
};

template <>
struct infmt<struct bitfmt_12be>: public _infmt<bitfmt_12be, 12> {
	static inline unsigned int as_uint(bitfmt_t v) {
		return be16toh(v.v) & 0xfff;
	}

	static inline bitfmt_t as_bitfmt(unsigned int v) {
		return bitfmt_t{ htobe16(v) };
	}
};

template <>
struct infmt<struct bitfmt_16be>: public _infmt<bitfmt_16be, 16> {
	static inline unsigned int as_uint(bitfmt_t v) {
		return be16toh(v.v);
	}

	static inline bitfmt_t as_bitfmt(unsigned int v) {
		return bitfmt_t{ htobe16(v) };
	}
};

// the optimization options
template <bool _round_2, bool _round_4>
struct avg_fixedopt {
	static bool const round_2	= _round_2;
	static bool const round_4	= _round_4;
};

struct avg_dynopt {
	bool const round_2;
	bool const round_4;

	avg_dynopt(bool round_2, bool round_4) :
		round_2(round_2), round_4(round_4) {
	}
};

template <typename INPIX, typename OUTPIX>
struct conversion {
	typedef INPIX				pixin_t;
	typedef OUTPIX				pixout_t;

	typedef struct infmt<pixin_t>		fmtin_t;
	typedef struct outfmt<pixout_t>		fmtout_t;
};

#endif	/* HH_ENSC_BAYER_RGB_CONVERT_INTERNAL_HH */
